package ac.il.technion.c236369.hw4.core.queues;

import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;

import ac.il.technion.c236369.hw4.configuration.ServerConfig;
import ac.il.technion.c236369.hw4.core.queues.exception.NotEnoughtPlaceInQueue;

/**
 * @author Artem Barger, Maxim Aizenshtein
 *
 *	Storage class to keep incoming sockets in the FIFO list.
 *
 */
public class SocketQueue {
	
	private static SocketQueue instance = new SocketQueue( );
	private List<Socket> sockets = new ArrayList<Socket>( );
	private final Logger log = Logger.getLogger( SocketQueue.class);
	
	final public static Socket NULL_SOCKET = new Socket( );
	final private ExecutorService pool = Executors.newFixedThreadPool( ServerConfig.getInstance().getProperties().getSocketQueue());
	
	
	private SocketQueue( ) {
		
	}

	public static synchronized SocketQueue getInstance() {
		return instance;
	}

	/**
	 * Insert new incoming socket inside queue.
	 * 
	 * @param socket
	 */
	public synchronized void tryAdd( Socket socket){
		if ( sockets.size( ) > ServerConfig.getInstance().getProperties().getSocketQueue()) {
			log.info( "Socket queue size limit is exceeded, queue size is: <" + sockets.size( ) + "");
			pool.execute( new InsertSocketQueue(socket));
		}
		sockets.add( sockets.size( ), socket);
	}
	
	public synchronized void add( Socket socket) throws NotEnoughtPlaceInQueue{
		if ( sockets.size( ) > ServerConfig.getInstance().getProperties().getSocketQueue()) {
			log.info( "Socket queue size limit is exceeded, queue size is: <" + sockets.size( ) + "");
			throw new NotEnoughtPlaceInQueue( );
		}
		sockets.add( sockets.size( ), socket);
	}
	
	
	
	/**
	 * @return next socket in the queue, in case there are no
	 * currently socket in the queue returns NULL_SOCKET reference.
	 */
	public synchronized Socket get( ) {
		if ( sockets.isEmpty( ))
			return NULL_SOCKET;
		return sockets.remove(0);
	}
}
